package com.tamtamy.jttamobile;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyStore;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ByteArrayBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

import android.content.Context;
import android.util.Log;

import com.tamtamy.jttamobile.constant.Type;
import com.tamtamy.jttamobile.data.Comment;
import com.tamtamy.jttamobile.data.CommentList;
import com.tamtamy.jttamobile.data.Content;
import com.tamtamy.jttamobile.data.ContentFile;
import com.tamtamy.jttamobile.data.ContentLink;
import com.tamtamy.jttamobile.data.ContentList;
import com.tamtamy.jttamobile.data.ContentMessage;
import com.tamtamy.jttamobile.data.ContentQuestion;
import com.tamtamy.jttamobile.data.ContentWidget;
import com.tamtamy.jttamobile.data.GroupDetails;
import com.tamtamy.jttamobile.data.GroupList;
import com.tamtamy.jttamobile.data.Metadata;
import com.tamtamy.jttamobile.data.NetworkDetails;
import com.tamtamy.jttamobile.data.NetworkList;
import com.tamtamy.jttamobile.data.Notice;
import com.tamtamy.jttamobile.data.NoticeList;
import com.tamtamy.jttamobile.data.OnLineUsersList;
import com.tamtamy.jttamobile.data.TagDetail;
import com.tamtamy.jttamobile.data.TagList;
import com.tamtamy.jttamobile.data.Token;
import com.tamtamy.jttamobile.data.UserDetail;
import com.tamtamy.jttamobile.data.UserStatsGenerationDetails;
import com.tamtamy.jttamobile.data.UserStatsGenerationList;
import com.tamtamy.jttamobile.data.UserStatsList;
import com.tamtamy.jttamobile.data.UserTag;
import com.tamtamy.jttamobile.data.UsersList;
import com.tamtamy.jttamobile.exception.JTTAException;
import com.tamtamy.jttamobile.exception.ParsingException;
import com.tamtamy.jttamobile.exception.UnauthorizedException;
import com.tamtamy.jttamobile.parser.JSONParser;
import com.tamtamy.jttamobile.parser.Parser;
import com.tamtamy.jttamobile.utility.APIUtility;



/**
 * TamTamyAPI class sets up the parameters and handle the calls to the resources via URI statements.<br>
 * Uses the <b>jtta.properties</b> file to load configuration settings and the 
 * <a href="http://hc.apache.org/httpclient-3.x/" target="_new">Apache commons-httpclient</a> to manage 
 * http requests and responses from the resource.
 * 
 * @author Omar "0m4r" Adobati 
 * @version %I%, %G% 
 * 
 */

public class  JTTAClient {
	private static final String TAG = JTTAClient.class.getSimpleName(); 
	private static final String COMMENT_COMMENT = "comment.comment";
	private static final String COMMENT_CONTENT_ID = "comment.contentId";
	private static final String TOKEN = "token";
	/**
	 * Holds the application name that uses jTTA
	 */	
	public static final String APP_PROPERTIES = "conf/jtta.properties";

	protected static DefaultHttpClient httpClient;
	public static final String DEF_ENCODING = "UTF-8";

	private String type;
	private boolean debug = false;
	private String version;

	private String username;
	private String password;

	private Parser parser;
	//private JTTAProperties properties = null;
	private String  hostName;
	private String protocol;
	private APIUtility apiUtility;

	protected Token token;
	
	/**
	 * Class constructor.
	 * 
	 * @see HttpClient
	 * @see #url
	 * @see #version
	 * @see #type
	 * @see #debug
	 * @see #instances
	 */
	public JTTAClient(Context context) { 
		super();
		apiUtility = new APIUtility(protocol, hostName, Type.JSON, debug);
		parser = new JSONParser(apiUtility);
		prepareHttpclient();
	}

	private void prepareHttpclient(){
		if(httpClient==null){
			// porkaround per catena certificati
			 try {
			        KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
			        trustStore.load(null, null);

			        SSLSocketFactory sf = new JTTASSLSocketFactory(trustStore);
			        sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

			        HttpParams params = new BasicHttpParams();
			        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
			        HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);

			        SchemeRegistry registry = new SchemeRegistry();
			        registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
			        registry.register(new Scheme("https", sf, 443));

			        ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);

			        httpClient = new DefaultHttpClient(ccm, params);
			    } catch (Exception e) {
			    	httpClient = new DefaultHttpClient();
			    }

		}
	}

	/**
	 * Calls the login URI to access the resource to execute the login
	 * @see	com.tamtamy.jttamobile.data.Token
	 * @param usr	username to login
	 * @param pwd	password to login
	 */	

	public void doLogin() throws JTTAException {
		doLogin(this.username, this.password);
	}

	public void doLogin(String username, String password) throws JTTAException {
		try {
			token = parser.doLogin(URLEncoder.encode(username, DEF_ENCODING), URLEncoder.encode(password, DEF_ENCODING));
		} catch (UnauthorizedException unauthorizedException) {
			throw new JTTAException(unauthorizedException);
		} catch (UnsupportedEncodingException unsupportedEncodingException) {
			throw new JTTAException(unsupportedEncodingException);
		}
	}
	
	public void tryLogin(String tamtamyUrl, String username, String password) throws JTTAException {
		try {
			token = parser.tryLogin(tamtamyUrl,URLEncoder.encode(username, DEF_ENCODING), URLEncoder.encode(password, DEF_ENCODING));
		} catch (UnauthorizedException unauthorizedException) {
			throw new JTTAException(unauthorizedException);
		} catch (UnsupportedEncodingException unsupportedEncodingException) {
			throw new JTTAException(unsupportedEncodingException);
		}
	}

	public boolean isValidToken(String username, String token) throws JTTAException {
		try {
			return parser.isValidToken(URLEncoder.encode(username, DEF_ENCODING), token);
		}catch (UnsupportedEncodingException unsupportedEncodingException) {
			throw new JTTAException(unsupportedEncodingException);
		}
	}

	/**
	 * Calls the logout URI to access the resource to execute the logout
	 * @throws JTTAException 
	 */

	public void doLogout() throws JTTAException {
		parser.doLogout();
		token = null;
	}

	/**
	 * Calls the URI to access the resource to have back the complete Tag List
	 * @see	com.tamtamy.jttamobile.data.TagList
	 * @return	com.omar.labs.tamtamy.TagList
	 * @throws JTTAException 
	 */
	public TagList getTagList(long startOffset, long limit) throws JTTAException {	
		TagList tagList = new TagList();
		tagList = parser.getTagList(startOffset,limit);
		if (debug){
			Log.d(TAG,  "[getTagList] " +
					"(startOffset:" + startOffset + 
					",limit:" 		+ limit + ")\n" + 
					tagList.toString());
		}
		return tagList;		
	}

	/**
	 * Calls the URI to access the resource to have back the complete Tag Details information
	 * @see	com.tamtamy.jttamobile.data.TagDetail
	 * @see	com.tamtamy.jtta.data.xml.XMLTagDetail
	 * @param tag	name of the tag
	 * @return	com.omar.labs.tamtamy.TagDetail
	 * @throws JTTAException 
	 */
	public TagDetail getTagDetail(String tag) throws JTTAException {
		TagDetail tagDetail = new TagDetail();
		tagDetail = parser.getTagDetail(tag);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getTagDetail] " +
					"(tag:" + tag + ")\n" + 
					tagDetail.toString());
		}
		return tagDetail;
	}

	/**
	 * Calls the URI to access the resource to have back the complete Content List
	 * @see	com.tamtamy.jtta.data.xml.XMLContentList
	 * @see	com.tamtamy.jttamobile.data.Content
	 * @see com.tamtamy.jttamobile.data.ContentFilter
	 * @see com.tamtamy.jttamobile.data.ContentOrder
	 * @param startOffset starting point int the list
	 * @param limit number of items to display
	 * @param filter 
	 * @param order
	 * @return	com.omar.labs.tamtamy.ContentList
	 * @throws JTTAException 
	 * 
	 */
	public ContentList getContentList(long startOffset, long limit, String filter, String order) throws JTTAException {
		ContentList contentList = new ContentList();
		try {
			contentList = parser.getContentList(startOffset,limit,filter,order);
			if (debug && contentList!=null){
				Log.d(TAG,  "[getContentList] " +
						"(startOffset:" + startOffset + 
						",limit:" 		+ limit + 
						",filter:" 		+ filter + 
						",order:" 		+ order + ")\n" + 
						contentList.toString());
			}
		} catch (ParsingException parsingException) {
			throw new JTTAException(parsingException);
		}
		return contentList;		
	}			

	public Content getContent(String contentID) throws JTTAException {
		Content content = new Content();
		content = parser.getContent(contentID);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getContentFile] " +
					"(contentID:" + contentID + ")\n" + 
					content.toString());
		}
		return content;	
	}




	/**
	 * Calls the URI to access the resource to have back the Content File information
	 * @see	com.tamtamy.jttamobile.data.ContentFile
	 * @see	com.tamtamy.jtta.data.xml.XMLContentFile
	 * @param	contentID the content ID
	 * @return	com.omar.labs.tamtamy.ContentFile
	 * @throws JTTAException 
	 */
	public Content getContentFile(String contentID) throws JTTAException {
		Content contentFile = new ContentFile();
		contentFile = parser.getContentFile(contentID);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getContentFile] " +
					"(contentID:" + contentID + ")\n" + 
					contentFile.toString());
		}
		return contentFile;	
	}

	/**
	 * Calls the URI to access the resource to have back the Content Link information
	 * @see	com.tamtamy.jttamobile.data.ContentFile
	 * @see	com.tamtamy.jtta.data.xml.XMLContentLink
	 * @param	contentID the content ID
	 * @return	com.omar.labs.tamtamy.ContentLink
	 * @throws JTTAException 
	 */
	public ContentLink getContentLink(String contentID) throws JTTAException {
		ContentLink contentLink = new ContentLink();
		contentLink = parser.getContentLink(contentID);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getContentLink] " +
					"(contentID:" + contentID + ")\n" + 
					contentLink.toString());
		}
		return contentLink;	
	}

	/**
	 * Calls the URI to access the resource to have back the Content Message information
	 * @see	com.tamtamy.jttamobile.data.ContentFile
	 * @see	com.tamtamy.jtta.data.xml.XMLContentMessage
	 * @param	contentID the content ID
	 * @return	com.omar.labs.tamtamy.ContentMessage
	 * @throws JTTAException 
	 */
	public ContentMessage getContentMessage(String contentID) throws JTTAException {
		ContentMessage contentMessage = parser.getContentMessage(contentID);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getContentMessage] " +
					"(contentID:" + contentID + ")\n" + 
					contentMessage.toString());
		}
		return contentMessage;	
	}

	/**
	 * Calls the URI to access the resource to have back the Content Widget information
	 * @see	com.tamtamy.jttamobile.data.ContentFile
	 * @see	com.tamtamy.jtta.data.xml.XMLContentWidget
	 * @param	contentID the content ID
	 * @return	com.omar.labs.tamtamy.ContentWidget
	 * @throws JTTAException 
	 */
	public ContentWidget getContentWidget(String contentID) throws JTTAException {
		ContentWidget  contentWidget = parser.getContentWidget(contentID);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getContentWidget] " +
					"(contentID:" + contentID + ")\n" + 
					contentWidget.toString());
		}
		return  contentWidget;	
	}

	/**
	 * Calls the URI to access the resource to have back the Comment List
	 * @see	com.tamtamy.jttamobile.data.Content
	 * @see	com.tamtamy.jttamobile.data.ContentList
	 * @see	com.tamtamy.jtta.data.xml.XMLCommentList
	 * @param startOffset starting point
	 * @param 	limit number of items to display
	 * @return	com.omar.labs.tamtamy.CommentList
	 * @throws JTTAException 
	 */
	public CommentList getCommentList(long startOffset, long limit) throws JTTAException {
		CommentList commentList = null;
		try {
			commentList = parser.getCommentList(startOffset, limit);
			if (debug){
				Log.d(this.getClass().getSimpleName(), "[getCommentList] " +
						"(startOffset:" + startOffset + 
						",limit:" 		+ limit + ")\n" + 
						commentList.toString());
			}
		} catch (ParsingException parsingException) {
			throw new JTTAException(parsingException);
		} 
		return commentList;	
	}
	
	/**
	 * Calls the URI to access the resource to have back the Comment List
	 * @see	com.tamtamy.jttamobile.data.Content
	 * @see	com.tamtamy.jttamobile.data.ContentList
	 * @see	com.tamtamy.jtta.data.xml.XMLCommentList
	 * @param startOffset starting point
	 * @param 	limit number of items to display
	 * @return	com.omar.labs.tamtamy.CommentList
	 * @throws JTTAException 
	 */
	public CommentList getCommentsList(long contentID, long startOffset, long limit) throws JTTAException {
		CommentList commentList = null;
		try {
			commentList = parser.getCommentsList(contentID, startOffset, limit);
		} catch (ParsingException parsingException) {
			throw new JTTAException(parsingException);
		} 
		return commentList;	
	}

	/**
	 * Calls the URI to access the resource to have back the Comment item
	 * @see	com.tamtamy.jttamobile.data.Content
	 * @see	com.tamtamy.jttamobile.data.ContentList
	 * @see	com.tamtamy.jtta.data.xml.XMLComment
	 * @param	contents the content ID
	 * @return	com.omar.labs.tamtamy.Comment
	 * @throws JTTAException 
	 */
	public Comment getComment(long commentID) throws JTTAException {
		Comment comment = null;
		try {
			comment = parser.getComment(commentID);
			if (debug){
				Log.d(this.getClass().getSimpleName(), "[getComment] " +
						"(commentID:" + commentID + ")\n" + 
						comment.toString());
			}			
		} catch (ParsingException pe){
			throw new JTTAException(pe);
		}
		return comment;	
	}

	/**
	 * Calls the URI to access the resource to have back the Notice List
	 * @see	com.tamtamy.jttamobile.data.Content
	 * @see	com.tamtamy.jttamobile.data.NoticeList
	 * @see	com.tamtamy.jtta.data.xml.XMLNoticeList
	 * @see com.tamtamy.jttamobile.data.NoticeContent
	 * @see com.tamtamy.jttamobile.data.NoticeContentComment
	 * @see com.tamtamy.jttamobile.data.NoticeBlog
	 * @see com.tamtamy.jttamobile.data.NoticeWiki
	 * @see com.tamtamy.jttamobile.data.NoticeForum
	 * @see com.tamtamy.jttamobile.data.NoticeUser
	 * @see com.tamtamy.jttamobile.data.NoticeUserTagging
	 * @param 	startOffset starting point
	 * @param 	limit number of items to display
	 * @param 	filter
	 * @return	com.omar.labs.tamtamy.CommentList
	 * @throws JTTAException 
	 */
	public NoticeList getNoticeList(long startOffset, long limit, String filter, String userId, String fromDate, String toDate) throws JTTAException {
		NoticeList noticeList = null;
		try {
			noticeList = parser.getNoticeList(startOffset, limit, filter, userId, fromDate, toDate);
			if (debug){
				Log.d(this.getClass().getSimpleName(), "[getNoticeList] " +
						"(startOffset:" + startOffset + 
						",limit:" 		+ limit + 
						",filter:" 		+ filter + ")\n" + 
						noticeList.toString());
			}
		} catch (ParsingException parsingException) {
			throw new JTTAException(parsingException);
		} 
		return noticeList;	
	}

	/**
	 * Calls the URI to access the resource to have back the Notice
	 * @see	com.tamtamy.jttamobile.data.Content
	 * @see	com.tamtamy.jttamobile.data.NoticeList
	 * @see	com.tamtamy.jtta.data.xml.XMLNoticeList
	 * @see com.tamtamy.jttamobile.data.NoticeContent
	 * @see com.tamtamy.jttamobile.data.NoticeContentComment
	 * @see com.tamtamy.jttamobile.data.NoticeBlog
	 * @see com.tamtamy.jttamobile.data.NoticeWiki
	 * @see com.tamtamy.jttamobile.data.NoticeForum
	 * @see com.tamtamy.jttamobile.data.NoticeUser
	 * @see com.tamtamy.jttamobile.data.NoticeUserTagging
	 * @param 	noticeID 
	 * @return	com.omar.labs.tamtamy.CommentList
	 * @throws JTTAException 
	 */
	public Notice getNotice(long noticeID) throws JTTAException {
		Notice notice = parser.getNotice(noticeID);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getNotice] " +
					"(noticeID:" + noticeID + ")\n" + 
					notice.toString());
		}
		return notice;	
	}

	public UserStatsList getUserStatsList(String userID, long startOffset, long limit) throws JTTAException  {
		UserStatsList userStats = parser.getUserStatsList(userID, startOffset, limit);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getUserStatsList] " +
					"(userID:" 		+ userID + 
					",startOffset:" + startOffset + 
					",limit:" 		+ limit + ")\n" + 
					userStats.toString());
		}	
		return userStats;	
	}

	public UserStatsGenerationList getUserStatsGenerationList(long startOffset, long limit) throws JTTAException {
		UserStatsGenerationList userStatsGenerationList = null;
		try {
			userStatsGenerationList = parser.getUserStatsGenerationList(startOffset, limit);
			if (debug){
				Log.d(this.getClass().getSimpleName(), "[getUserStatsGenerationList] " +
						"(startOffset:" + startOffset + 
						",limit:" 		+ limit + ")\n" + 
						userStatsGenerationList.toString());
			}
		} catch (ParsingException parsingException) {
			throw new JTTAException(parsingException);
		} 
		return userStatsGenerationList;	
	}

	public UserStatsGenerationDetails getUserStatsGenerationDetails(String userStatsID, long startOffset, long limit) throws JTTAException {
		UserStatsGenerationDetails userStatsGenerationDetails  = parser.getUserStatsGenerationDetails(userStatsID, startOffset, limit);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getUserStatsGenerationDetails] " +
					"(userStatsID:" + userStatsID + 
					",startOffset:" + startOffset + 
					",limit:" 		+ limit + ")\n" + 
					userStatsGenerationDetails.toString());
		}

		return userStatsGenerationDetails;	
	}

	public GroupList getGroupList(long startOffset, long limit) throws JTTAException {
		GroupList groupList = null;	
		try {
			groupList = parser.getGroupList(startOffset, limit);
			if (debug){
				Log.d(this.getClass().getSimpleName(), "[getGroupList] " +
						"(startOffset:" + startOffset + 
						",limit:" 		+ limit + ")\n" + 
						groupList.toString());
			}
		} catch (ParsingException parsingException) {
			throw new JTTAException(parsingException);
		} 	
		return groupList;	
	}

	public GroupDetails getGroupDetails(String groupID) throws JTTAException {
		GroupDetails groupDetails = parser.getGroupDetails(groupID);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getGroupDetails] " +
					"(groupID:" + groupID + ")\n" + 
					groupDetails.toString());
		}

		return groupDetails;	
	}

	public NetworkList getNetworkList(long startOffset, long limit, String filter) throws JTTAException {
		NetworkList networkList = new NetworkList();
		try {
			networkList = parser.getNetworkList(startOffset, limit, filter);
			if (debug){
				Log.d(this.getClass().getSimpleName(), "[getNetworkList] " +
						"(startOffset:" + startOffset + 
						",limit:" 		+ limit + 
						",filter:" 		+ filter + ")\n" + 
						networkList.toString());
			}
		}  catch (ParsingException parsingException) {
			throw new JTTAException(parsingException);
		} 
		return networkList;	
	}

	public NetworkList getNetworkList(long startOffset, long limit) throws JTTAException {
		NetworkList networkList = null;
		try {
			networkList = parser.getNetworkList(startOffset, limit);
			if (debug){
				Log.d(this.getClass().getSimpleName(), "[getNetworkList] " +
						"(startOffset:" + startOffset + 
						",limit:" 		+ limit + ")\n" + 
						networkList.toString());
			}
		} catch (ParsingException parsingException) {
			throw new JTTAException(parsingException);
		} 
		return networkList;	
	}


	public NetworkList getNetworkListWithChatEnabled(long startOffset, long limit, String filter) throws JTTAException {
		NetworkList networkListWithChatEnabled = null;
		try {
			networkListWithChatEnabled = parser.getNetworkListWithChatEnabled(startOffset, limit, filter);
			if (debug){
				Log.d(this.getClass().getSimpleName(), "[getNetworkListWithChatEnabled] " +
						"(startOffset:" + startOffset + 
						",limit:" 		+ limit + 
						",filter:" 		+ filter + ")\n" + 
						networkListWithChatEnabled.toString());
			}
		}  catch (ParsingException parsingException) {
			throw new JTTAException(parsingException);
		} 
		return networkListWithChatEnabled;	
	}

	public NetworkList getNetworkListWithChatEnabled(long startOffset, long limit) throws JTTAException {
		NetworkList networkListWithChatEnabled = new NetworkList();
		try {
			networkListWithChatEnabled = parser.getNetworkListWithChatEnabled(startOffset, limit);
			if (debug){
				Log.d(this.getClass().getSimpleName(), "[getNetworkListWithChatEnabled] " +
						"(startOffset:" + startOffset + 
						",limit:" 		+ limit + ")\n" + 
						networkListWithChatEnabled.toString());
			}
		} catch (ParsingException parsingException) {
			throw new JTTAException(parsingException);
		} 
		return networkListWithChatEnabled;	
	}

	public NetworkDetails getNetworkDetails(String networkID) throws JTTAException {
		NetworkDetails networkDetails = parser.getNetworkDetails(networkID);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getNetworkDetails] " +
					"(networkID:" + networkID + ")\n" + 
					networkDetails.toString());
		}
		return networkDetails;	
	}

	public Metadata getMetadata(String url) throws JTTAException {
		Metadata metadata =  null;
		try {
			metadata = parser.getMetadata(url);
			if (debug){
				Log.d(this.getClass().getSimpleName(), "[getMetadata] " +
						"(url:" + url + ")\n" + 
						metadata.toString());
			}
		}  catch (ParsingException exception) {
			throw new JTTAException(exception);
		}
		return metadata;	
	}

	public UserTag getUserTag(String filter) throws JTTAException {
		UserTag userTag = parser.getUserTag(filter);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getUserTag] " +
					"(filter:" + filter + ")\n" + 
					userTag.toString());
		}

		return userTag;	
	}

	public UserTag getUserTag(String userID, String filter) throws JTTAException {
		UserTag userTag = parser.getUserTag(userID, filter);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getUserTag] " +
					"(userID:" 	+ userID + 
					",filter:" 	+ filter + ")\n" + 
					userTag.toString());
		}
		return userTag;	
	}

	/**
	 * Calls the URI to access the resource to have back the complete User List
	 * @see	com.tamtamy.jttamobile.data.UsersList
	 * @see	com.tamtamy.jtta.data.xml.XMLUsersList
	 * @return	com.omar.labs.tamtamy.XML.XMLUsersList
	 * @throws JTTAException 
	 */
	public UsersList getUsersList(long startOffset, long limit, String filter) throws JTTAException {
		UsersList userList = null;
		try {
			userList = parser.getUsersList(startOffset, limit, filter);
			if (debug){
				Log.d(this.getClass().getSimpleName(), "[getUsersList] " +
						"(startOffset:" + startOffset + 
						",limit:" 		+ limit + 
						",filter:" 		+ filter + ")\n" + 
						userList.toString());
			}
		} catch (ParsingException parsingException) {
			throw new JTTAException(parsingException);
		} 	
		return userList;				
	}

	/**
	 * Calls the URI to access the resource to have back the complete On-Line User List
	 * @see	com.tamtamy.jttamobile.data.OnLineUsersList
	 * @see	com.tamtamy.jtta.data.xml.XMLOnLineUsersList
	 * @return	com.omar.labs.tamtamy.XML.XMLOnLineUsersList
	 * @throws JTTAException 
	 */ 	 
	public OnLineUsersList getOnLineUsersList(long startOffset, long limit) throws JTTAException {
		OnLineUsersList onLineUsersList = parser.getOnLineUsersList(startOffset, limit);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getOnLineUsersList] " +
					"(startOffset:" + startOffset + 
					",limit:" 		+ limit + ")\n" + 
					onLineUsersList.toString());
		}
		return onLineUsersList;	
	}

	/**
	 * Calls the URI to access the resource to have back the User Detail
	 * @see	com.tamtamy.jttamobile.data.UserDetail
	 * @see	com.tamtamy.jtta.data.xml.XMLUserDetail
	 * @param userID
	 * @return	com.omar.labs.tamtamy.XML.XMLUserDetail	 
	 * @throws JTTAException 
	 */
	public UserDetail getUserDetail(String userID) throws JTTAException {
		if(token == null) {
			return null;
		}
		UserDetail userDetail = parser.getUserDetail(userID);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[getUserDetail] " + "(userID:" + userID + ")\n" + userDetail.toString());
		}
		return userDetail;	
	}

	public void downloadContent(String contentID) throws JTTAException {
		parser.downloadContent(contentID);
		if (debug){
			Log.d(this.getClass().getSimpleName(), "[downloadContent] " +
					"(contentID:" + contentID + ")\n");
		}
	}

	/*
	public void setProxy(String hostname, int port, String username, String password) {
		this.getParams().setAuthenticationPreemptive(true);
		HostConfiguration hostConfiguration = this.getHostConfiguration();
		hostConfiguration.setProxy(hostname, port);
		HttpState state = this.getState();
		Credentials proxyCredentials = new UsernamePasswordCredentials(username, password);
		state.setProxyCredentials(AuthScope.ANY, proxyCredentials);
	}
	 */

	public String getType() {
		return type;
	}

	public void setType(String type) {
		this.type = type;
	}

	public String getVersion() {
		return version;
	}

	public void setVersion(String version) {
		this.version = version;
	}

	public boolean isDebug() {
		return debug;
	}

	public void setDebug(boolean debug) {
		this.debug = debug;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	/** POST **/

	/**
	 * Perform a post call to a system, the parameter must be passed in a NameVaaluePair list
	 * @param nameValuePairs  parameter to inseert in the call
	 * @param contentURL  url to call
	 * @return
	 * @throws UnsupportedEncodingException
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	protected int postCall(List<NameValuePair> nameValuePairs, String contentURL) throws UnsupportedEncodingException, IOException,	ClientProtocolException {
		return postCall(nameValuePairs, null, contentURL);
	}

	protected int postCall(List<NameValuePair> nameValuePairs, MultipartEntity entity, String contentURL) throws UnsupportedEncodingException, IOException, ClientProtocolException {

		HttpPost httppost = new HttpPost(contentURL);    
		if(entity!=null) //image or attachment
			httppost.setEntity(entity);
		else
			httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs, DEF_ENCODING));

		HttpResponse httpResponse = httpClient.execute(httppost);
		String responseLine = httpResponse.getStatusLine().getReasonPhrase();
		int responseCode = httpResponse.getStatusLine().getStatusCode();
		Log.d(TAG,  "url: " + contentURL + " responseCode: " + responseCode + "\n responseLine: " + responseLine);
		httpResponse.getEntity().consumeContent();
		nameValuePairs = null;
		entity = null;
		return responseCode;
	}

	private List<NameValuePair> postContent(Content newContent){
		List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
		nameValuePairs.add((new BasicNameValuePair("token", token.getToken())));
		nameValuePairs.add((new BasicNameValuePair("content.type", newContent.getType())));
		nameValuePairs.add((new BasicNameValuePair("content.title", newContent.getTitle())));
		nameValuePairs.add((new BasicNameValuePair("content.description", newContent.getDescription())));
		String languageCode = newContent.getLanguageCode();
		if(null==languageCode) languageCode="en";
		nameValuePairs.add((new BasicNameValuePair("content.languageCode", languageCode)));
		String permission = newContent.getPermission();
		if(null==permission) permission="1";
		nameValuePairs.add((new BasicNameValuePair("content.permission", permission)));
		String rateEnabled = newContent.getRateEnabled();
		if(null==rateEnabled) permission="true";
		nameValuePairs.add((new BasicNameValuePair("content.rateEnabled", rateEnabled)));
		StringBuilder tags = new StringBuilder();
		for (String tag : newContent.getTags()) {
			if(tags.length() >0 ) {
				tags.append(", ");
			}
			tags.append(tag);
		}
		nameValuePairs.add((new BasicNameValuePair("tagList", tags.toString())));
		return nameValuePairs;
	}

	public int postContentMessage(ContentMessage newContent) throws UnsupportedEncodingException, ClientProtocolException, IOException{
		newContent.setContentType(Content.CONTENT_TYPE_MESSAGE);
		List<NameValuePair> nameValuePairs = postContent(newContent);

		String contentURL = apiUtility.getPostContentURL();
		if(debug)
			Log.d(TAG,  newContent.toString());
		int responseCode = postCall(nameValuePairs, contentURL);
		return responseCode;
	}

	public int postContentFile(ContentFile newContent, byte[] attachement) throws UnsupportedEncodingException, ClientProtocolException, IOException{
		newContent.setContentType(Content.CONTENT_TYPE_FILE);
		List<NameValuePair> nameValuePairs = postContent(newContent);
		String fileName = newContent.getContentFileName();
		if(null==fileName) {
			fileName = "photo.jpg";
		}
		nameValuePairs.add((new BasicNameValuePair("fileFileName", fileName)));
		MultipartEntity entity = new MultipartEntity();
		for (NameValuePair i : nameValuePairs) {
			String name = i.getName();
			String value = i.getValue();
			value=null==value?"":value;
			entity.addPart(name, new StringBody(value));
		}
		if (attachement!=null) {
			entity.addPart("file", new ByteArrayBody(attachement, fileName));
		}

		String contentURL = apiUtility.getPostContentURL();
		if(debug)
			Log.d(TAG,  newContent.toString());
		int responseCode = postCall(nameValuePairs, entity, contentURL);
		//if(entity!=null)
		//	entity.consumeContent();
		return responseCode;
	}

	public int postContentLink(ContentLink newContent) throws UnsupportedEncodingException, ClientProtocolException, IOException{
		newContent.setContentType(Content.CONTENT_TYPE_LINK);
		List<NameValuePair> nameValuePairs = postContent(newContent);
		nameValuePairs.add((new BasicNameValuePair("content.contentUrl", newContent.getContentUrl())));

		String contentURL = apiUtility.getPostContentURL();
		if(debug)
			Log.d(TAG, newContent.toString());
		int responseCode = postCall(nameValuePairs, contentURL);
		return responseCode;
	}

	public int postContentQuestion(ContentQuestion newContent) throws UnsupportedEncodingException, ClientProtocolException, IOException{
		newContent.setContentType(Content.CONTENT_TYPE_QUESTION);
		List<NameValuePair> nameValuePairs = postContent(newContent);
		nameValuePairs.add((new BasicNameValuePair("questionExpirationDate", newContent.getQuestionExpirationDate())));
		nameValuePairs.add((new BasicNameValuePair("questionCategoryIds", newContent.getQuestionCategoryIds())));

		String contentURL = apiUtility.getPostContentURL();
		if(debug)
			Log.d(TAG, newContent.toString());
		int responseCode = postCall(nameValuePairs, contentURL);
		return responseCode;
	}

	public int postComment(String contentId, String commentText ) throws JTTAException {
		int result;
		Log.d(TAG, "token: " + token.getToken());
		Log.d(TAG, "contentId: " + contentId);
		Log.d(TAG, "commentText: " + commentText);
		try {
			List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(); 
			nameValuePairs.add(new BasicNameValuePair(TOKEN, token.getToken()));
			nameValuePairs.add((new BasicNameValuePair(COMMENT_CONTENT_ID, contentId)));
			nameValuePairs.add((new BasicNameValuePair(COMMENT_COMMENT, commentText)));
			String contentURL = apiUtility.getBaseUrl() + "/comment."+Type.JSON.toLowerCase();
			if(debug)
				Log.d(TAG, commentText);
			result = postCall(nameValuePairs, contentURL);
			if(result >=400) {
				throw new JTTAException("Wrong response code:"+result);
			}
		} catch (UnsupportedEncodingException e) {
			Log.e(this.getClass().getSimpleName(), commentText, e);
			throw new JTTAException(e);
		} catch (ClientProtocolException e) {				
			Log.e(this.getClass().getSimpleName(), commentText, e);
			throw new JTTAException(e);
		} catch (IOException e) {
			Log.e(this.getClass().getSimpleName(), commentText, e);
			throw new JTTAException(e);
		}

		return result;
	}

	public String getHostName() {
		return hostName;
	}

	public void setConnectionParam(boolean secure, String hostName) {
		String protocol = secure?"https":"http";
		this.hostName = hostName;
		apiUtility.setHostName(hostName);
		apiUtility.setProtocol(protocol);
		//reset actual httpClient implementation
		httpClient = null;
		prepareHttpclient();
	}

	public String getTamtamyUrl(){
		return apiUtility.getTamTamyUrl();
	}

	/**
	 * @param jttaClient
	 * @param url
	 * @param httpRequest
	 * @param debug
	 * @return
	 * @throws UnauthorizedException
	 */
	public static String getResponse(HttpUriRequest httpRequest) throws JTTAException {
		InputStream in = null;
		String response = null;
		HttpResponse httpResponse;
		try {
			Log.d(TAG, "httpRequest.getURI(): " + httpRequest.getURI());
			httpResponse = httpClient.execute(httpRequest);
			int statusCode = httpResponse.getStatusLine().getStatusCode();
			//String statusLine = httpResponse.getStatusLine().getReasonPhrase();
			if (statusCode!=200){
				//consume thee content so it should not keep open the connection
				try { httpResponse.getEntity().consumeContent();}catch(Exception e){}
				throw new JTTAException("code " + statusCode);
			}
			in = httpResponse.getEntity().getContent();

			//
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			StringBuffer sb = new StringBuffer("");
			String line = "";
			String NL = System.getProperty("line.separator");
			while ((line = br.readLine()) != null) {
				sb.append(line + NL);
			}
			in.close();
			httpResponse.getEntity().consumeContent();
			response = sb.toString();
			//
		} catch (Exception exception) {
			JTTAException jtta = new JTTAException("Error calling " + httpRequest.getURI() + " : " + exception.getLocalizedMessage());
			jtta.initCause(exception);
			throw jtta;
		}

		return response;
	}

	public static HttpEntity getHttpEntity(String url) throws ClientProtocolException, IOException {
		HttpGet request = new HttpGet(url);
		HttpResponse response =httpClient.execute(request);
		
		return response.getEntity();
	}

	public void setAppName(String appName) {
		apiUtility.setAppName(appName);
	}
	
	public boolean hasToken() {
		return token != null && token.getToken() != null;
	}
	
	public void resetToken() {
		token = null;
	}

}
